package com.czl.module_base.mvp.presenter;

import android.app.Activity;
import android.app.Service;
import android.util.Log;
import android.view.View;

import androidx.core.app.ComponentActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;

import com.czl.module_base.http.HttpResponse;
import com.czl.module_base.http.RetryWithDelay;
import com.czl.module_base.mvp.model.IModel;
import com.czl.module_base.mvp.view.IView;
import com.czl.module_base.observer.AbsHandleSubscriber;
import com.czl.module_base.system.HttpConstants;
import com.trello.rxlifecycle3.RxLifecycle;

import java.lang.ref.SoftReference;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;


/**
 * @author xubin
 * @date on 2018/9/14  11:16
 */
public class BasePresenter<M extends IModel, V extends IView> implements IPresenter, LifecycleObserver {

    protected final String TAG = this.getClass().getSimpleName();
    protected CompositeDisposable mCompositeDisposable;
    protected M mModel;
    protected V mView;

    private SoftReference<IView> mReferenceView;

    protected int mPageNo = 1;

    public int getPageNo() {
        return mPageNo;
    }

    public void resetPageNo(boolean refresh) {
        if (refresh) {
            mPageNo = 1;
        }
    }

    public void nextPageNo() {
        mPageNo++;
    }

    @Override
    public void onStart(IView view) {
        //使用软引用创建对象
        mReferenceView = new SoftReference<>(view);
        //使用动态代理做统一的逻辑判断 aop 思想
        mView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), (o, method, objects) -> {
            if (mReferenceView == null || mReferenceView.get() == null) {
                return null;
            }
            return method.invoke(mReferenceView.get(), objects);
        });

        //通过获得泛型类的父类，拿到泛型的接口类实例，通过反射来实例化 model
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        if (type != null) {
            Type[] types = type.getActualTypeArguments();
            try {
                mModel = (M) ((Class<?>) types[0]).newInstance();
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }

        //将 LifecycleObserver 注册给 LifecycleOwner 后 @OnLifecycleEvent 才可以正常使用
        if (mView != null && mView instanceof LifecycleOwner) {
            ((LifecycleOwner) mView).getLifecycle().addObserver(this);
            if (mModel != null && mModel instanceof LifecycleObserver) {
                ((LifecycleOwner) mView).getLifecycle().addObserver((LifecycleObserver) mModel);
            }
        }
    }

    protected <T> void doSubscribe(
            Observable<HttpResponse<T>> observable,
            AbsHandleSubscriber<HttpResponse<T>> observer
    ) {
        doSubscribe(observable, observer, true, false, null);
    }

    protected <T> void doSubscribe(
            Observable<HttpResponse<T>> observable,
            AbsHandleSubscriber<HttpResponse<T>> observer,
            boolean showLoading
    ) {
        doSubscribe(observable, observer, showLoading, false, null);
    }

    protected <T> void doSubscribe(
            Observable<HttpResponse<T>> observable,
            AbsHandleSubscriber<HttpResponse<T>> observer,
            String title
    ) {
        doSubscribe(observable, observer, false, true, title);
    }

    protected <T> void doSubscribe(
            Observable<HttpResponse<T>> observable,
            AbsHandleSubscriber<HttpResponse<T>> observer,
            boolean showLoading, boolean showDialog, String title
    ) {
        observable
                .doOnSubscribe(disposable -> {
                    addDispose(disposable);
                    if (showLoading) {
                        mView.showLoading();
                    }
                    if (showDialog) {
                        mView.showDialogLoading(title);
                    }
                })
                .retryWhen(new RetryWithDelay(HttpConstants.MAX_RETRIES, HttpConstants.RETRY_DELAY_SECOND))
                .compose(rxSchedulerHelper())
                .doFinally(() -> {
                    if (showLoading) {
                        mView.hideDialogLoading();
                    }
                    if (showDialog) {
                        mView.hideDialogLoading();
                    }
                })
                .subscribe(observer);

    }

    protected <T> void doSubscribe2(
            Observable<HttpResponse<T>> observable,
            AbsHandleSubscriber<HttpResponse<T>> observer
    ) {
        doSubscribe(observable, observer, false, true, "加载中");
    }

    protected <T> void doSubscribe2(
            Observable<HttpResponse<T>> observable,
            AbsHandleSubscriber<HttpResponse<T>> observer,
            boolean showDialog
    ) {
        doSubscribe(observable, observer, false, showDialog, null);
    }

    protected <T> void doSubscribe2(
            Observable<HttpResponse<? extends T>> observable,
            AbsHandleSubscriber<HttpResponse<? extends T>> observer,
            boolean showDialog, String title
    ) {
        observable.compose(subscribe(false, showDialog, title))
                .subscribe(observer);
    }

    protected <T> void doSubscribe3(
            Observable<T> observable,
            AbsHandleSubscriber<T> observer
    ) {
        doSubscribe3(observable, observer, false, true, "加载中");
    }

    protected <T> void doSubscribe3(
            Observable<T> observable,
            AbsHandleSubscriber<T> observer,
            String title
    ) {
        doSubscribe3(observable, observer, false, true, title);
    }

    protected <T> void doSubscribe3(
            Observable<T> observable,
            AbsHandleSubscriber<T> observer,
            boolean showLoading, boolean showDialog, String title
    ) {
        observable.compose(subscribe(showLoading, showDialog, title))
                .subscribe(observer);

    }

    protected <T> ObservableTransformer<T, T> subscribe(boolean showLoading, boolean showDialog, String title) {
        return upstream -> upstream
                .doOnSubscribe(disposable -> {
                    addDispose(disposable);
                    if (showLoading) {
                        mView.showLoading();
                    }
                    if (showDialog) {
                        mView.showDialogLoading(title);
                    }
                })
                .retryWhen(new RetryWithDelay(HttpConstants.MAX_RETRIES, HttpConstants.RETRY_DELAY_SECOND))
                .compose(rxSchedulerHelper())
                .doFinally(() -> {
                    if (showDialog) {
                        mView.hideDialogLoading();
                    }
                });
    }

    protected <T> ObservableTransformer<T, T> rxSchedulerHelper() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(this::addDispose);
    }

    /**
     * onDestroy
     */
    @Override
    public void onDestroy() {
        //解除订阅
        unDispose();
        if (mModel != null) {
            mModel.onDestroy();
        }
        this.mModel = null;
        this.mView = null;
        this.mCompositeDisposable = null;
        if (mReferenceView != null) {
            mReferenceView.clear();
            mReferenceView = null;
        }
    }

    /**
     * 只有当 {@code mRootView} 不为 null, 并且 {@code mRootView} 实现了 {@link LifecycleOwner} 时, 此方法才会被调用
     * 所以当您想在 {@link Service} 以及一些自定义 {@link View} 或自定义类中使用 {@code Presenter} 时
     * 您也将不能继续使用 {@link OnLifecycleEvent} 绑定生命周期
     *
     * @param owner link {@link ComponentActivity} and {@link Fragment}
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy(LifecycleOwner owner) {
        /*
          注意, 如果在这里调用了 {@link #onDestroy()} 方法, 会出现某些地方引用 {@code mModel} 或 {@code mRootView} 为 null 的情况
          比如在 {@link RxLifecycle} 终止 {@link Observable} 时, 在 {@link io.reactivex.Observable#doFinally(Action)} 中却引用了 {@code mRootView} 做一些释放资源的操作, 此时会空指针
          或者如果你声明了多个 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 时在其他 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
          中引用了 {@code mModel} 或 {@code mRootView} 也可能会出现此情况
         */
        owner.getLifecycle().removeObserver(this);
    }

    /**
     * 将 {@link Disposable} 添加到 {@link CompositeDisposable} 中统一管理
     * 可在 {@link Activity onDestroy()} 中使用 {@link #unDispose()} 停止正在执行的 RxJava 任务,避免内存泄漏
     * 目前框架已使用 {@link RxLifecycle} 避免内存泄漏,此方法作为备用方案
     *
     * @param disposable disposable
     */
    public void addDispose(Disposable disposable) {
        if (mCompositeDisposable == null) {
            mCompositeDisposable = new CompositeDisposable();
        }
        //将所有 Disposable 放入集中处理
        mCompositeDisposable.add(disposable);
    }

    /**
     * 停止集合中正在执行的 RxJava 任务
     */
    @Override
    public void unDispose() {
        Log.e(TAG, "取消订阅");
        if (mCompositeDisposable != null) {
            //保证 Activity 结束时取消所有正在执行的订阅
            mCompositeDisposable.clear();
        }
        if (mModel != null) {
            mModel.unDispose();
        }
    }
}
